<?php
/**
 * Description:
 * Author: hezhizheng
 * Date: 2018/11/13
 * Time: 17:04
 * Created by Created by Panxsoft.
 */

namespace App\Models;

use App\Models\Concerns\ModelMemorable;
use App\Services\MobileApp\AppEnv;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 *
 * @property int currency_id
 * @property string symbol_left
 * @property string symbol_right
 * @property int decimal_place - 保留小数的位数
 * @property string value - 汇率转换倍率（产品价格 x value = 对应货币价格）
 * @property string code
 *
 * @mixin Builder
 */
class Currency extends Model
{
    use ModelMemorable;

    const STATUS_ENABLE = 1;
    const STATUS_DISABLE = 0;

    /**
     * @deprecated
     */
    const CODE_CNY = 'CNY';
    /**
     * @deprecated
     */
    const CODE_DEFAULT = self::CODE_CNY;

    // 跟默认语言ID一样，这个值应该不能被删除
    const CURRENCY_ID_DEFAULT = 4;

    const CURRENCY_MINIMUM_PRICE = 0.01; // 支付的最小价格

    protected $guarded = [];

    protected $table = 'currency';
    protected $primaryKey = 'currency_id';

    protected $casts = [
        'decimal_place' => 'int',
    ];

    public const UPDATED_AT = 'date_modified';

    public static function allCurrency()
    {
        return (new self)->where('status',self::STATUS_ENABLE)->get();
    }

    /**
     * @return Currency|Currency[]|\Illuminate\Database\Eloquent\Collection|Model|null|object
     */
    public static function fromEnv(): self
    {
        return AppEnv::currency();
    }

    /**
     * @param $store_id
     * @return Currency|Currency[]|\Illuminate\Database\Eloquent\Collection|Model|null|object
     */
    public static function getCurrencyAttr($store_id)
    {
        $currency_code = request()->currency ?? self::getStoreSettingCurrencyCode($store_id);
        $currency = (new self)
            ->where('status', self::STATUS_ENABLE)
            ->where('code', $currency_code)
            ->latest('currency_id')
            ->first();

        if (! $currency) {
            return (new self)->find(self::CURRENCY_ID_DEFAULT);
        }

        return $currency;
    }

    /**
     *  获取店铺设置的系统默认货币
     *
     * @return Currency|Currency[]|\Illuminate\Database\Eloquent\Collection|Model|null|object
     */
    public static function getCurrencyDefault()
    {
        $currency_code = self::getStoreSettingCurrency();
        $currency = (new self)
            ->where('status', self::STATUS_ENABLE)
            ->where('code', $currency_code)
            ->latest('currency_id')
            ->first();

        if (! $currency) {
            return (new self)->find(self::CURRENCY_ID_DEFAULT);
        }

        return $currency;
    }

    /**
     * @deprecated (用下面的了)
     * @return mixed
     */
    public static function getStoreSettingCurrency()
    {
       $setting =  Setting::findConfigByCode(Setting::CODE_CONFIG);

       return $setting['config_currency'];
    }

    /**
     * @param int $store_id
     * @return mixed
     */
    public static function getStoreSettingCurrencyCode(int $store_id)
    {
        $configs = Setting::findConfigByCode(Setting::CODE_CONFIG, $store_id);

        if (isset($configs['config_currency'])) {
            return $configs['config_currency'];
        } else {
            throw new \LogicException("Store [$store_id] setting config currency code missing");
        }
    }

    /**
     * 客户提交的价格和货币，转换成店铺默认货币的价格。
     * @param $exchange_price
     * @param Currency $currency
     * @return string
     */
    public static function transformStoreSettingCurrencyPrice($exchange_price, Currency $currency)
    {
//        $price = bcdiv($exchange_price, $currency->value, $currency->decimal_place);
        // 改成与 oc 逻辑一致（oc网页上并没有价格区间搜索， 后端商品管理也只能搜索指定价格，不能搜索区间）
        $price = round($exchange_price / $currency->value, $currency->decimal_place);

        return $price;
    }

    /**
     * 商品的价格，使用设定的汇率转化价格
     *
     * @example 必须安装 bcmath 如 yum install php71w-bcmath
     *
     * @param $price
     *
     * @return string
     */
    public function exchangePrice($price): string
    {
        /**
         * 参考 \dw-oc\system\library\cart\currency.php -> \Cart\Currency::format
         * bc库对精度的处理是直接切掉而不是取近似，可能导致 oc 与 app 数据不一致，暂时使用与 oc 相同的逻辑处理
         */
        $price = round($price * $this->value, $this->decimal_place);

        if ($price < self::CURRENCY_MINIMUM_PRICE) {
            $price = self::CURRENCY_MINIMUM_PRICE;
        }

        return number_format($price, $this->decimal_place, '.', '');

//        return bcmul($price, $this->value, $this->decimal_place);
    }

    /**
     * 商品选项的价格，使用设定的汇率转化价格
     *
     * @example 必须安装 bcmath 如 yum install php71w-bcmath
     *
     * @param $price
     *
     * @return string
     */
    public function exchangeOptionValuePrice($price): string
    {
        /**
         * 参考 \dw-oc\system\library\cart\currency.php -> \Cart\Currency::format
         * bc库对精度的处理是直接切掉而不是取近似，可能导致 oc 与 app 数据不一致，暂时使用与 oc 相同的逻辑处理
         */
        $price = round($price * $this->value, $this->decimal_place);

        return number_format($price, $this->decimal_place, '.', '');

//        return bcmul($price, $this->value, $this->decimal_place);
    }

    /**
     * 订单价格的处理, 根据order表的currency_value。
     *
     * @param $price
     * @param $currency_value
     * @return string
     */
    public function exchangeOriginPrice($price, $currency_value): string
    {
        /**
         * 参考 \dw-oc\system\library\cart\currency.php -> \Cart\Currency::format
         * bc库对精度的处理是直接切掉而不是取近似，可能导致 oc 与 app 数据不一致，暂时使用与 oc 相同的逻辑处理
         */
        $price = round($price * $currency_value, $this->decimal_place);

        return number_format($price, $this->decimal_place, '.', '');
    }

    /**
     * @param $currency_code
     * @param $value
     * @return string
     */
    public static function getProductTotalPriceByCurrency($currency_code, $value)
    {
        /** @var Currency $currency */
        $currency = (new self)
            ->where('status', self::STATUS_ENABLE)
            ->where('code', $currency_code)
            ->latest('currency_id')
            ->first();

        $product_total_value = $currency->exchangePrice($value);

        return $product_total_value;
    }

    /**
     * @param $code
     * @return Currency
     */
    public static function getCurrencyByCode($code)
    {
        /** @var Currency $currency */
        $currency = (new self)
            ->where('status', self::STATUS_ENABLE)
            ->where('code', $code)
            ->latest('currency_id')
            ->first();

        return $currency;
    }
}
